﻿// -----------------------------------------------------------------------
// Copyright (c) David Kean. All rights reserved.
// -----------------------------------------------------------------------
extern alias pcl;
using System;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BackgroundWorker = pcl::System.ComponentModel.BackgroundWorker;
using WinFormsApplication = System.Windows.Forms.Application;
using WpfApplication = System.Windows.Application;

namespace Portable.ComponentModel
{
    [TestClass]
    public class BackgroundWorkerIntegrationTests
    {
        [TestMethod]
        public void WindowsFormsIntegration()
        {   // Tests that the BackgroundWorker works with the WindowsFormsSynchronizationContext

            int currentThreadId = Thread.CurrentThread.ManagedThreadId;

            int progressCount = 0;

            var worker = CreateBackgroundWorker();
            worker.DoWork += (sender, e) => {

                // Should be called on a ThreadPool thread
                Assert.AreNotEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                while (!worker.CancellationPending)
                {
                    Thread.Sleep(10);
                    worker.ReportProgress(10);
                }

            };

            worker.ProgressChanged += (sender, e) => {

                // Should be called on the UI thread
                Assert.AreEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                if (progressCount == 10)
                    worker.CancelAsync();

                progressCount++;
            };

            worker.RunWorkerCompleted += (sender, e) => {

                // Should be called on the UI thread
                Assert.AreEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);
                WinFormsApplication.Exit();
            };

            // On idle we start running
            WinFormsApplication.Idle += (sender, e) =>
            {
                if (!worker.IsBusy)
                    worker.RunWorkerAsync();
            };

            // Start a message pump
            WinFormsApplication.Run();

            Assert.IsTrue(progressCount > 10);
        }

        [TestMethod]
        public void WindowsPresentationFoundationIntegration()
        {   // Tests that the BackgroundWorker works with the DispatcherSynchronizationContext

            int currentThreadId = Thread.CurrentThread.ManagedThreadId;

            int progressCount = 0;

            var worker = CreateBackgroundWorker();
            worker.DoWork += (sender, e) => {

                // Should be called on a ThreadPool thread
                Assert.AreNotEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                while (!worker.CancellationPending)
                {
                    Thread.Sleep(10);
                    worker.ReportProgress(10);
                }

            };

            worker.ProgressChanged += (sender, e) => {
                // Should be called on the UI thread
                Assert.AreEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                if (progressCount == 10)
                    worker.CancelAsync();

                progressCount++;
            };

            WpfApplication application = new WpfApplication();

            worker.RunWorkerCompleted += (sender, e) => {

                // Should be called on the UI thread
                Assert.AreEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);
                application.Shutdown();
            };

            application.Startup += (sender, e) => worker.RunWorkerAsync();

            // Start a message pump
            application.Run();

            Assert.IsTrue(progressCount > 10);
        }

        [TestMethod]
        public void DefaultSynchronizationContext()
        {   // Tests that the BackgroundWoker works with the default SynchronizationContext

            int currentThreadId = Thread.CurrentThread.ManagedThreadId;

            int progressCount = 0;

            var worker = CreateBackgroundWorker();
            worker.DoWork += (sender, e) => {

                // Should be called on a ThreadPool thread
                Assert.AreNotEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                while (!worker.CancellationPending)
                {
                    Thread.Sleep(10);
                    worker.ReportProgress(10);
                }
            };

            worker.ProgressChanged += (sender, e) =>
            {
                // Should be called on a ThreadPool thread
                Assert.AreNotEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);

                if (progressCount == 10)
                    worker.CancelAsync();

                progressCount++;
            };

            var wait = new EventWaitHandle(false, EventResetMode.ManualReset);
            
            worker.RunWorkerCompleted += (sender, e) =>
            {
                // Should be called on a ThreadPool thread
                Assert.AreNotEqual(currentThreadId, Thread.CurrentThread.ManagedThreadId);
                wait.Set();
            };

            worker.RunWorkerAsync();
            wait.WaitOne();

            Assert.IsTrue(progressCount > 10);
        }

        public static BackgroundWorker CreateBackgroundWorker()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;

            return worker;
        }
    }
}
